package com.windystory.wsbluetoothlibrary;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.content.DialogInterface;
import android.content.Intent;
import android.provider.Settings;
import android.widget.Toast;

import com.clj.fastble.BleManager;
import com.clj.fastble.callback.BleGattCallback;
import com.clj.fastble.callback.BleIndicateCallback;
import com.clj.fastble.callback.BleNotifyCallback;
import com.clj.fastble.callback.BleReadCallback;
import com.clj.fastble.callback.BleRssiCallback;
import com.clj.fastble.callback.BleScanAndConnectCallback;
import com.clj.fastble.callback.BleScanCallback;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleDevice;
import com.tbruyelle.rxpermissions2.RxPermissions;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

/**
 * 蓝牙manager
 */
public class BluetoothManager {

    private Activity activity;

    public BluetoothManager(Activity activity) {
        this.activity = activity;
    }

    /**
     * 初始化蓝牙
     *
     * @param showLog       是否显示日志 true显示 false不显示
     * @param count         连接时重连次数 int类型
     * @param interval      重连间隔（毫秒）
     * @param splitNum      分包发送的时候，每一包的数据长度，默认20个字节
     * @param timeOut       设置连接超时时间（毫秒），默认10秒
     * @param operationTime 设置readRssi、setMtu、write、read、notify、indicate的超时时间（毫秒），默认5秒
     */
    public void initBluetooth(final boolean showLog, final int count, final long interval, final int splitNum, final long timeOut, final int operationTime) {

        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (!bluetoothAdapter.isEnabled()) {
            Toast.makeText(activity, "请先打开蓝牙", Toast.LENGTH_LONG).show();
            return;
        }

        new RxPermissions(activity).request(
                Manifest.permission.ACCESS_FINE_LOCATION)
                .subscribe(new Observer<Boolean>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Boolean aBoolean) {
                        if (aBoolean) {
                            BleManager.getInstance().init(activity.getApplication());
                        } else {
                            new AlertDialog.Builder(activity)
                                    .setTitle("温馨提示")
                                    .setMessage("当前手机扫描蓝牙需要打开定位功能")
                                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialogInterface, int i) {
                                            activity.finish();
                                        }
                                    })
                                    .setPositiveButton("前往设置", new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialogInterface, int i) {
                                            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                                            activity.startActivity(intent);
                                        }
                                    })

                                    .setCancelable(false)
                                    .show();
                        }
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    /**
     * 扫描
     *
     * @param callback 回调接口
     *                 onScanStarted -- 开始扫描（主线程）
     *                 onScanning    -- 扫描到一个符合扫描规则的BLE设备（主线程）
     *                 onScanFinished-- 扫描结束，列出所有扫描到的符合扫描规则的BLE设备（主线程）
     *                 <p>
     *                 Tips:
     *                 - 扫描及过滤过程是在工作线程中进行，所以不会影响主线程的UI操作，
     *                 最终每一个回调结果都会回到主线程。
     */
    public void scan(BleScanCallback callback) {
        BleManager.getInstance().scan(callback);
    }

    /**
     * 扫描并连接
     *
     * @param callback 回调接口
     *                 <p>
     *                 onScanStarted(boolean success) 开始扫描（主线程）
     *                 onScanFinished(BleDevice scanResult) 扫描结束，结果即为扫描到的第一个符合扫描规则的BLE设备，如果为空表示未搜索到（主线程）
     *                 onStartConnect() 开始连接（主线程）
     *                 onConnectFail(BleDevice bleDevice,BleException exception) 连接失败（主线程）
     *                 onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) // 连接成功，BleDevice即为所连接的BLE设备（主线程）
     *                 onDisConnected(boolean isActiveDisConnected, BleDevice device, BluetoothGatt gatt, int status)  连接断开，isActiveDisConnected是主动断开还是被动断开（主线程）
     *                 <p>
     *                 Tips:
     *                 - 扫描及过滤过程是在工作线程中进行，所以不会影响主线程的UI操作，但每一个回调结果都会回到主线程。 连接操作会在主线中进行。
     */
    public void scanAndConnect(BleScanAndConnectCallback callback) {
        BleManager.getInstance().scanAndConnect(callback);
    }

    /**
     * 已知蓝牙设备信息蓝牙连接
     *
     * @param bleDevice       设备信息
     * @param bleGattCallback 回调接口
     *                        onStartConnect    -- 开始连接
     *                        onConnectFail     -- 连接失败
     *                        onConnectSuccess  -- 连接成功，BleDevice即为所连接的BLE设备
     *                        onDisConnected    -- 连接中断，isActiveDisConnected表示是否是主动调用了断开连接方法
     *                        <p>
     *                        Tips:
     *                        - 在某些型号手机上，connectGatt必须在主线程才能有效。非常建议把连接过程放在主线程。
     *                        - 连接失败后重连：框架中包含连接失败后的重连机制，可以配置重连次数和时间间隔。当然也可以自行在`onConnectFail`回调方法中延时调用`connect`方法。
     *                        - 连接断开后重连：可以在`onDisConnected`回调方法中再次调用`connect`方法。
     *                        - 为保证重连成功率，建议断开后间隔一段时间之后进行重连。
     *                        - 某些机型上连接失败后会短暂地无法扫描到设备，可以通过设备对象或设备mac直连，而不经过扫描。
     */
    public void connect(BleDevice bleDevice, BleGattCallback bleGattCallback) {
        BleManager.getInstance().connect(bleDevice, bleGattCallback);
    }

    /**
     * 已知mac地址蓝牙连接
     *
     * @param mac             设备mac信息
     * @param bleGattCallback 回调接口
     */
    public void connect(String mac, BleGattCallback bleGattCallback) {
        BleManager.getInstance().connect(mac, bleGattCallback);
    }

    /**
     * 取消扫描
     * Tips:
     * - 调用该方法后，如果当前还处在扫描状态，会立即结束，并回调`onScanFinished`方法。
     */
    public void cancelScan() {
        BleManager.getInstance().cancelScan();
    }


    /**
     * 写数据
     *
     * @param bleDevice
     * @param uuid_service
     * @param uuid_write
     * @param data
     * @param callback     onWriteSuccess(int current, int total, byte[] justWrite) 发送数据到设备成功
     *                     onWriteFailure(BleException exception)  发送数据到设备失败
     */
    public void write(BleDevice bleDevice,
                      String uuid_service,
                      String uuid_write,
                      byte[] data,
                      BleWriteCallback callback) {
        BleManager.getInstance().write(bleDevice, uuid_service, uuid_write, data, callback);
    }

    /**
     * 读数据
     *
     * @param bleDevice
     * @param uuid_service
     * @param uuid_read
     * @param callback     onReadSuccess(byte[] data)  读特征值数据成功
     *                     onReadFailure(BleException exception) 读特征值数据失败
     */
    public void read(BleDevice bleDevice,
                     String uuid_service,
                     String uuid_read,
                     BleReadCallback callback) {
        BleManager.getInstance().read(bleDevice, uuid_service, uuid_read, callback);
    }


    /**
     * 强度
     *
     * @param bleDevice 蓝牙设备
     * @param callback  回调接口
     *                  onRssiFailure(BleException exception)   读取设备的信号强度失败
     *                  onRssiSuccess(int rssi)  读取设备的信号强度成功
     */
    public void readRssi(BleDevice bleDevice, BleRssiCallback callback) {
        BleManager.getInstance().readRssi(
                bleDevice, callback);
    }


    /**
     * 断开某个设备
     *
     * @param bleDevice
     */
    public void disconnect(BleDevice bleDevice) {
        BleManager.getInstance().disconnect(bleDevice);
    }

    /**
     * 订阅通知notify
     *
     * @param bleDevice                   蓝牙设备
     * @param uuid_service
     * @param uuid_notify
     * @param useCharacteristicDescriptor
     * @param callback                    onNotifySuccess() 打开通知操作成功
     *                                    onNotifyFailure(BleException exception)  打开通知操作失败
     *                                    onCharacteristicChanged(byte[] data)  打开通知后，设备发过来的数据将在这里出现
     */
    public void notify(BleDevice bleDevice,
                       String uuid_service,
                       String uuid_notify,
                       boolean useCharacteristicDescriptor,
                       BleNotifyCallback callback) {
        BleManager.getInstance().notify(
                bleDevice,
                uuid_service,
                uuid_notify,
                useCharacteristicDescriptor,
                callback);
    }

    /**
     * 取消订阅通知notify，并移除数据接收的回调监听
     *
     * @param bleDevice
     * @param uuid_service
     * @param uuid_notify
     * @param useCharacteristicDescriptor
     */
    public void stopNotify(BleDevice bleDevice,
                           String uuid_service,
                           String uuid_notify,
                           boolean useCharacteristicDescriptor) {
        BleManager.getInstance().stopNotify(bleDevice, uuid_service, uuid_notify, useCharacteristicDescriptor);
    }

    /**
     * 订阅通知indicate
     *
     * @param bleDevice
     * @param uuid_service
     * @param uuid_indicate
     * @param useCharacteristicDescriptor
     * @param callback                    onIndicateSuccess()  打开通知操作成功
     *                                    onIndicateFailure(BleException exception) 打开通知操作失败
     *                                    onCharacteristicChanged(byte[] data)  打开通知后，设备发过来的数据将在这里出现
     */
    public void indicate(BleDevice bleDevice,
                         String uuid_service,
                         String uuid_indicate,
                         boolean useCharacteristicDescriptor,
                         BleIndicateCallback callback) {
        BleManager.getInstance().indicate(
                bleDevice,
                uuid_service,
                uuid_indicate,
                useCharacteristicDescriptor, callback);
    }

    /**
     * 取消订阅通知indicate，并移除数据接收的回调监听
     *
     * @param bleDevice
     * @param uuid_service
     * @param uuid_indicate
     * @param useCharacteristicDescriptor
     */
    public void stopIndicate(BleDevice bleDevice,
                             String uuid_service,
                             String uuid_indicate,
                             boolean useCharacteristicDescriptor) {
        BleManager.getInstance().stopIndicate(bleDevice, uuid_service, uuid_indicate, useCharacteristicDescriptor);
    }

    /**
     * 获取major private
     *
     * @param byteData
     * @return
     */
    public int getMajorInfo(String byteData) {
        try {
            return Integer.parseInt(byteData.substring(50, 54), 16);
        } catch (Exception e) {
            return -1;
        }
    }


    /**
     * 获取minor private
     *
     * @param byteData
     * @return
     */
    public int getMinorInfo(String byteData) {
        try {
            return Integer.parseInt(byteData.substring(54, 58), 16);
        } catch (Exception e) {
            return -1;
        }
    }

    /**
     * 获取UUID private
     *
     * @param byteData
     * @return
     */
    public int getUUID(String byteData) {
        try {
            return Integer.parseInt(byteData.substring(18, 50), 16);
        } catch (Exception e) {
            return -1;
        }
    }


}
